﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using Microsoft.Samples.Office.UnifiedCommunications.Gadget.Config;
using Microsoft.Samples.Office.UnifiedCommunications.Gadget.DTO;
using Microsoft.Samples.Office.UnifiedCommunications.Gadget.Events;

namespace Microsoft.Samples.Office.UnifiedCommunications.Gadget
{
    public partial class DesktopContacts : Page
    {
        #region Variables

        private DesktopContactCollection _desktopContacts = new DesktopContactCollection();
        private DesktopContact _desktopContact;

        public delegate void DesktopContactsChangedDelegate(DesktopContactChangedEventArgs e);

        #endregion

        public DesktopContacts()
        {
            InitializeComponent();

            this.Unloaded += new RoutedEventHandler(DesktopContacts_Unloaded);
            this.MouseDown += new MouseButtonEventHandler(DesktopContacts_MouseDown);

            this.btnHelp.MouseEnter += new MouseEventHandler(btnHelp_MouseEnter);
            this.btnHelp.MouseLeave += new MouseEventHandler(btnHelp_MouseLeave);

            GadgetEventManager.Instance.NotifyDesktopContactChangedEvent += 
                new EventHandler(Instance_NotifyDesktopContactChangedEvent);
        }

        #region Loading

        void BackDoubleAnimation_Completed(object sender, EventArgs e)
        {
            this.listContacts.ItemsSource = _desktopContacts;
        }

        void RefreshDesktopContacts()
        {
            _desktopContacts = new DesktopContactCollection();
            this.listContacts.ItemsSource = _desktopContacts;
        }

        #endregion

        #region Unloading

        void DesktopContacts_Unloaded(object sender, RoutedEventArgs e)
        {
            this.MouseDown -= new MouseButtonEventHandler(DesktopContacts_MouseDown);

            this.btnHelp.MouseEnter -= new MouseEventHandler(btnHelp_MouseEnter);
            this.btnHelp.MouseLeave -= new MouseEventHandler(btnHelp_MouseLeave);

            GadgetEventManager.Instance.NotifyDesktopContactChangedEvent -=
                new EventHandler(Instance_NotifyDesktopContactChangedEvent);
        }

        #endregion

        #region GadgetEventManager Event Handlers

        void Instance_NotifyDesktopContactChangedEvent(object sender, EventArgs e)
        {
            DesktopContactChangedEventArgs desktopContactChangedEventArgs = e as DesktopContactChangedEventArgs;

            BackgroundWorker workerContactsChanged = new BackgroundWorker();
            workerContactsChanged.WorkerReportsProgress = false;
            workerContactsChanged.WorkerSupportsCancellation = false;

            DesktopContactsChangedDelegate delegateDesktopContactsChanged = null;

            workerContactsChanged.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                delegateDesktopContactsChanged = new DesktopContactsChangedDelegate(NotifyContactChangedEvent_DoWork);

                this.Dispatcher.Invoke(DispatcherPriority.Background,
                    delegateDesktopContactsChanged, desktopContactChangedEventArgs);
            };

            workerContactsChanged.RunWorkerAsync();
        }

        #endregion

        #region Desktop Contacts CRUD

        void AddDesktopContact(int contactId, string sipUri)
        {
            tbMessage.Text = String.Empty;

            if (!DesktopContactAlreadyExists(sipUri))
            {
                // Raise an event to the Gadget window
                //  The Gadget window will verify the contact and raise an event to notify this window.
                //
                DesktopContactChangedEventArgs args = new DesktopContactChangedEventArgs()
                {
                    Operation = DesktopContactOperation.Add,
                    AffectedContact = new DesktopContact
                    {
                        ContactId = contactId,
                        SipUri = sipUri,
                        DisplayName = default(string),
                        Visible = true
                    }
                };

                GadgetEventManager.Instance.OnDesktopContactChangedEvent(args);
            }
            else
            {
                gridMessage.Visibility = Visibility.Visible;
                tbMessage.Text = String.Format("The Contact {0} is already in your list.", sipUri);
                RefreshDesktopContacts();
            }
        }

        void DeleteDesktopContact(int contactId)
        {
            DesktopContactElementCollection desktopContacts = GadgetConfigurationManager.GetDesktopContacts();
            DesktopContactElement desktopContactElement = desktopContacts.GetByContactId(contactId);

            if (desktopContactElement != null)
            {
                string displayName = desktopContactElement.DisplayName;

                DesktopContact contactToRemove = new DesktopContact()
                {
                    ContactId = desktopContactElement.ContactId,
                    SipUri = desktopContactElement.SipUri,
                    DisplayName = desktopContactElement.DisplayName,
                    Visible = desktopContactElement.Visible
                };

                GadgetConfigurationManager.RemoveDesktopContactById(contactId);

                gridMessage.Visibility = Visibility.Visible;
                tbMessage.Text = String.Format("Removed {0} from your contact list", displayName);

                GadgetEventManager.Instance.OnDesktopContactChangedEvent(
                    new DesktopContactChangedEventArgs()
                    {
                        Operation = DesktopContactOperation.Remove,
                        AffectedContact = contactToRemove
                    });

                RefreshDesktopContacts();
            }
        }

        void ModifyDesktopContactDisplayName()
        {
            string oldText = default(string);
            string newText = default(string);

            int contactId = _desktopContact.ContactId; // was set in TextBox_GotFocus

            DesktopContactElementCollection desktopContacts = GadgetConfigurationManager.GetDesktopContacts();
            DesktopContactElement desktopContactElement = desktopContacts.GetByContactId(contactId);

            if (desktopContactElement == null)
                return;
            else
                oldText = desktopContactElement.DisplayName;

            if (String.IsNullOrEmpty(oldText))
                return;

            newText = _desktopContact.DisplayName;

            if (!oldText.Equals(newText, StringComparison.OrdinalIgnoreCase))
                GadgetConfigurationManager.EditDesktopContactDisplayName(contactId, newText);

            GadgetEventManager.Instance.OnDesktopContactChangedEvent(
                new DesktopContactChangedEventArgs()
                    {
                        Operation = DesktopContactOperation.Modify,
                        AffectedContact = new DesktopContact()
                            {
                                ContactId = contactId,
                                SipUri = _desktopContact.SipUri,
                                DisplayName = newText,
                                Visible = _desktopContact.Visible
                            }
                    });
        }

        void ModifyDesktopContactVisibility(int contactId, bool visible) 
        {
            DesktopContactElementCollection desktopContacts = GadgetConfigurationManager.GetDesktopContacts();
            DesktopContactElement desktopContactElement = desktopContacts.GetByContactId(contactId);

            if (!Boolean.Equals(visible, desktopContactElement.Visible))
                GadgetConfigurationManager.EditDesktopContactVisibility(contactId, visible);

            DesktopContactOperation operation = visible ? DesktopContactOperation.Open : DesktopContactOperation.Remove;

            GadgetEventManager.Instance.OnDesktopContactChangedEvent(
                new DesktopContactChangedEventArgs()
                {
                    Operation = operation,
                    AffectedContact = new DesktopContact()
                    {
                        ContactId = contactId,
                        SipUri = desktopContactElement.SipUri,
                        DisplayName = desktopContactElement.DisplayName,
                        Visible = visible
                    }
                });
        }

        void NotifyContactChangedEvent_DoWork(DesktopContactChangedEventArgs e)
        {
            gridMessage.Visibility = Visibility.Visible;

            if (e.Operation == DesktopContactOperation.Mismatch)
            {
                tbMessage.Text = String.Format("Didn't recognize {0} as a valid Contact.", e.AffectedContact.SipUri);
            }
            else if (e.Operation == DesktopContactOperation.Add)
            {
                tbMessage.Text = String.Format("Added {0} to your Desktop Contacts.", e.AffectedContact.DisplayName);
            }
            if (e.Operation == DesktopContactOperation.Remove)
            {
                tbMessage.Text = String.Format("Removed {0} from your Desktop Contacts.", e.AffectedContact.DisplayName);
            }

            RefreshDesktopContacts();
        }

        void Object_Drop(object sender, DragEventArgs e)
        {
            gridMessage.Visibility = Visibility.Collapsed;

            try
            {
                Label lblContact = sender as Label;

                string dropstring = (string)(e.Data.GetData(DataFormats.Text, true));

                if (String.IsNullOrEmpty(dropstring))
                    throw new Exception();

                lblContact.Content = dropstring;

                Point location = Mouse.GetPosition(this);   // Get the mouse position
                VisualTreeHelper.HitTest(this, null,        // Hit test to find ContactId
                    new HitTestResultCallback(HitTestCallBack),
                    new PointHitTestParameters(location));

                // Hit test sets listbox selected item
                int contactId = ((DesktopContact)listContacts.SelectedItem).ContactId;

                AddDesktopContact(contactId, dropstring);
            }
            catch
            {
                gridMessage.Visibility = Visibility.Visible;
                tbMessage.Text = String.Concat("Could not add this to your contacts. ",
                    "Did not recognize the item as a Communicator Contact.");
            }
        }

        HitTestResultBehavior HitTestCallBack(HitTestResult result)
        {
            if (VisualTreeHelper.GetParent(result.VisualHit) is ListBoxItem)
            {
                ItemContainerGenerator generator = this.listContacts.ItemContainerGenerator;
                ListBoxItem contactItem = (ListBoxItem)VisualTreeHelper.GetParent(result.VisualHit);
                int rowIndex = generator.IndexFromContainer(contactItem);
                DesktopContact desktopContact = (DesktopContact)listContacts.Items[rowIndex];
                listContacts.SelectedItem = desktopContact;
            }

            return HitTestResultBehavior.Continue;
        }

        bool DesktopContactAlreadyExists(string sipUri)
        {
            bool exists = false;

            DesktopContactElementCollection desktopContacts = GadgetConfigurationManager.GetDesktopContacts();

            foreach (DesktopContactElement desktopContactElement in desktopContacts)
            {
                if (desktopContactElement.SipUri == sipUri)
                {
                    exists = true;
                    break;
                }
            }

            return exists;
        }

        #endregion    

        #region Other UI Functionality

        void btnApply_Click(object sender, RoutedEventArgs e)
        {
            this.listContacts.UnselectAll();
        }

        void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            SettingsWindow.Instance.Close();
        }

        void btnHelp_MouseEnter(object sender, MouseEventArgs e)
        {
            (base.FindResource("fadeIn") as Storyboard).Begin(this.tooltip);
        }

        void btnHelp_MouseLeave(object sender, MouseEventArgs e)
        {
            (base.FindResource("fadeOut") as Storyboard).Begin(this.tooltip);
        }

        void imgDelete_MouseDown(object sender, MouseButtonEventArgs e)
        {
            int contactId = Convert.ToInt32(((Image)sender).Tag);
            DeleteDesktopContact(contactId);
        }

        void TextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            _desktopContact = (DesktopContact)listContacts.SelectedItem;
        }

        void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            if (((TextBox)sender).Name == "txtContactDisplayName") // The only TextBox that's enabled for editing
            {
                ModifyDesktopContactDisplayName();
            }
        }

        void DesktopContacts_MouseDown(object sender, MouseButtonEventArgs e)
        {
            this.listContacts.UnselectAll();
        }

        void chkVisible_Checked(object sender, RoutedEventArgs e)
        {
            ModifyDesktopContactVisibility(Convert.ToInt32((sender as CheckBox).Tag), true);
        }

        void chkVisible_Unchecked(object sender, RoutedEventArgs e)
        {
            ModifyDesktopContactVisibility(Convert.ToInt32((sender as CheckBox).Tag), false);
        }

        #endregion
    }
}